package tardisdatadepositor;

import monash.med.crystallography.DataSetTools.DiffdumpXML.DiffdumpXML;
import java.io.BufferedReader;
import javax.xml.bind.Unmarshaller;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Date;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

import trdDatafile.jaxb.Datafile;
import trdDataset2.jaxb.Dataset;

import mods.jaxb.AbstractType;
import mods.jaxb.CodeOrText;
import mods.jaxb.GenreType;
import mods.jaxb.IdentifierType;
import mods.jaxb.LocationType;
import mods.jaxb.ModsType;
import mods.jaxb.NamePartType;
import mods.jaxb.NameType;
import mods.jaxb.NameTypeAttribute;
import mods.jaxb.ObjectFactory;
import mods.jaxb.OriginInfoType;
import mods.jaxb.RelatedItemType;
import mods.jaxb.RoleType;
import mods.jaxb.TitleInfoType;
import mods.jaxb.UrlType;

import com.sun.xml.bind.marshaller.NamespacePrefixMapper;

import edu.harvard.hul.ois.mets.Agent;
import edu.harvard.hul.ois.mets.AmdSec;
import edu.harvard.hul.ois.mets.Checksumtype;
import edu.harvard.hul.ois.mets.Div;
import edu.harvard.hul.ois.mets.DmdSec;
import edu.harvard.hul.ois.mets.FLocat;

import edu.harvard.hul.ois.mets.FileGrp;
import edu.harvard.hul.ois.mets.FileSec;
import edu.harvard.hul.ois.mets.Fptr;
import edu.harvard.hul.ois.mets.Loctype;
import edu.harvard.hul.ois.mets.MdWrap;
import edu.harvard.hul.ois.mets.Mdtype;
import edu.harvard.hul.ois.mets.Mets;
import edu.harvard.hul.ois.mets.MetsHdr;
import edu.harvard.hul.ois.mets.Name;
import edu.harvard.hul.ois.mets.Role;
import edu.harvard.hul.ois.mets.StructMap;
import edu.harvard.hul.ois.mets.TechMD;
import edu.harvard.hul.ois.mets.Type;
import edu.harvard.hul.ois.mets.XmlData;
import edu.harvard.hul.ois.mets.helper.MetsException;
import edu.harvard.hul.ois.mets.helper.MetsWriter;
import edu.harvard.hul.ois.mets.helper.PCData;
import edu.harvard.hul.ois.mets.helper.PreformedXML;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;


public class Packager extends NamespacePrefixMapper
{

	public ArrayList<DatasetInfo> getDatasetInfo()
	{
		return datasetInfo;
	}

	public ExperimentInfo getExperimentInfo()
	{
		return experimentInfo;
	}

	private Mets mets;
	private ArrayList<DatasetInfo> datasetInfo;
	private ExperimentInfo experimentInfo;

	public Packager(ArrayList<DatasetInfo> datasetInfo, ExperimentInfo experimentInfo)
	{

		super();

		this.datasetInfo = datasetInfo;
		this.experimentInfo = experimentInfo;

	}

	@SuppressWarnings("unchecked")
	private void writeTARDISdatafile(AmdSec amdSec, String techMDid, String trdDatafileXML)
	{
		// TARDIS

		TechMD techMD = new TechMD();
		techMD.setID(techMDid);

		MdWrap mdWrap = new MdWrap();

		mdWrap.setMDTYPE(Mdtype.OTHER);
		mdWrap.setOTHERMDTYPE("TARDISDATAFILE");

		XmlData xmlData = new XmlData();

		PreformedXML preformed = new PreformedXML(trdDatafileXML); // TODO
		// :
		// unmarshall
		// me
		// !

		xmlData.getContent().add(preformed);

		mdWrap.getContent().add(xmlData);

		techMD.getContent().add(mdWrap);

		amdSec.getContent().add(techMD);
	}

	@SuppressWarnings("unchecked")
	private void writeTARDISdataset(AmdSec amdSec, String techMDid, String trdDatasetXML)
	{
		// TARDIS

		TechMD techMD = new TechMD();
		techMD.setID(techMDid);

		MdWrap mdWrap = new MdWrap();

		mdWrap.setMDTYPE(Mdtype.OTHER);
		mdWrap.setOTHERMDTYPE("TARDISDATASET");

		XmlData xmlData = new XmlData();

		PreformedXML preformed = new PreformedXML(trdDatasetXML); // TODO
		// :
		// unmarshall
		// me
		// !

		xmlData.getContent().add(preformed);

		mdWrap.getContent().add(xmlData);

		techMD.getContent().add(mdWrap);

		amdSec.getContent().add(techMD);
	}

	@SuppressWarnings("unchecked")
	private void writeAgent(MetsHdr metsHdr, Role role, Type type, String nameString)
	{
		Agent agent = new Agent();
		agent.setROLE(role);
		agent.setTYPE(type);
		Name name = new Name();
		name.getContent().add(new PCData(nameString));
		agent.getContent().add(name);

		metsHdr.getContent().add(agent);
	}

	@SuppressWarnings("unchecked")
	private void writeMODS(String dmdid, String MODSxml)
	{
		DmdSec dmdSec = new DmdSec();
		dmdSec.setID(dmdid);

		MdWrap mdWrap = new MdWrap();
		mdWrap.setMDTYPE(Mdtype.MODS);

		XmlData xmlData = new XmlData();

		PreformedXML preformed = new PreformedXML(MODSxml);

		xmlData.getContent().add(preformed);

		mdWrap.getContent().add(xmlData);

		dmdSec.getContent().add(mdWrap);

		mets.getContent().add(dmdSec);
	}

	@SuppressWarnings("unchecked")
	private void writePREMIS(AmdSec amdSec, String techMDid)
	{
		TechMD techMD = new TechMD();
		techMD.setID(techMDid);

		MdWrap mdWrap = new MdWrap();
		mdWrap.setMDTYPE(Mdtype.PREMIS);

		XmlData xmlData = new XmlData();

		PreformedXML preformed = new PreformedXML(""
				+ "\n<premis:object xmlns:premis=\"http://www.loc.gov/standards/premis\">"
				+ "\n<premis:objectIdentifier>"
				+ "\n<premis:objectIdentifierType>internal</premis:objectIdentifierType>"
				+ "\n<premis:objectIdentifierValue>J-1</premis:objectIdentifierValue>" + "\n</premis:objectIdentifier>"
				+ "\n<premis:preservationLevel>level 1</premis:preservationLevel>"
				+ "\n<premis:objectCategory>Representation</premis:objectCategory>" + "\n</premis:object>" + "\n");

		xmlData.getContent().add(preformed);

		mdWrap.getContent().add(xmlData);

		techMD.getContent().add(mdWrap);

		amdSec.getContent().add(techMD);
	}

	// Filegrp
	// ID
	// Size
	// Mimetype
	// Ownerid
	// Checksum
	// Checksumtype
	// URL
	@SuppressWarnings("unchecked")
	private edu.harvard.hul.ois.mets.File writeFileInformation(String id, long size, String mimeType, String ownerid, String checkSum,
			Checksumtype checksumType, String url, String admid)
	{
		edu.harvard.hul.ois.mets.File file = new edu.harvard.hul.ois.mets.File();
		file.setID(id);
		file.setSIZE(size);
		file.setMIMETYPE(mimeType);
		file.setOWNERID(ownerid);
		file.setCHECKSUM(checkSum);
		file.setCHECKSUMTYPE(checksumType);
		file.setADMID(admid);

		FLocat floLocat = new FLocat();
		floLocat.setLOCTYPE(Loctype.URL);
		floLocat.setXlinkHref(url);

		file.getContent().add(floLocat);

		return file;

	}

	@SuppressWarnings("unchecked")
	private edu.harvard.hul.ois.mets.File writeFileInformation(String id, long size, String mimeType, String ownerid, String checkSum,
			Checksumtype checksumType, String url)
	{
		edu.harvard.hul.ois.mets.File file = new edu.harvard.hul.ois.mets.File();
		file.setID(id);
		file.setSIZE(size);
		file.setMIMETYPE(mimeType);
		file.setOWNERID(ownerid);
		file.setCHECKSUM(checkSum);
		file.setCHECKSUMTYPE(checksumType);

		FLocat floLocat = new FLocat();
		floLocat.setLOCTYPE(Loctype.URL);
		floLocat.setXlinkHref(url);

		file.getContent().add(floLocat);

		return file;

	}

	private Div writeExperiment(String dmdid, String admid)
	{
		Div e_Div = new Div();
		e_Div.setTYPE("investigation");
		e_Div.setDMDID(dmdid);
		e_Div.setADMID(admid);

		return e_Div;
	}

	private Div writeDataset(Div experimentDiv, String dmdid, String admid)
	{
		Div d_Div = new Div();
		d_Div.setTYPE("dataset");
		d_Div.setDMDID(dmdid);
		d_Div.setADMID(admid);

		return d_Div;
	}

	private Div writeDataset(Div experimentDiv, String dmdid)
	{
		Div d_Div = new Div();
		d_Div.setTYPE("dataset");
		d_Div.setDMDID(dmdid);

		return d_Div;
	}

	private Fptr writeFilePointer(String fileid)
	{
		Fptr fptr = new Fptr();
		fptr.setFILEID(fileid);

		return fptr;
	}

	private String getMODSDataset(DatasetInfo datasetInfo)
	{
		ByteArrayOutputStream out = new ByteArrayOutputStream();

		try
		{
			JAXBContext jaxbContext = JAXBContext.newInstance("mods.jaxb");

			ObjectFactory objFactory = new ObjectFactory();

			ModsType mods = objFactory.createModsType();

			TitleInfoType titleInfo = objFactory.createTitleInfoType();

			titleInfo.getTitleOrSubTitleOrPartNumber().add(
					objFactory.createBaseTitleInfoTypeTitle(datasetInfo.getDescription()));

			mods.getModsGroup().add(titleInfo);

			// write

			Marshaller marshaller = jaxbContext.createMarshaller();

			marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", this);
			marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, new Boolean(true));
			marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);

			marshaller.marshal(mods, out);

		} catch (JAXBException j)
		{
			j.printStackTrace();
		}

		return out.toString();
	}

	private String getMODSExperiment(ExperimentInfo experimentInfo)
	{
		ByteArrayOutputStream out = new ByteArrayOutputStream();

		try
		{
			JAXBContext jaxbContext = JAXBContext.newInstance("mods.jaxb");

			ObjectFactory objFactory = new ObjectFactory();

			ModsType mods = objFactory.createModsType();

			// title

			TitleInfoType titleInfo = objFactory.createTitleInfoType();

			titleInfo.getTitleOrSubTitleOrPartNumber().add(
					objFactory.createBaseTitleInfoTypeTitle(experimentInfo.getTitle()));

			mods.getModsGroup().add(titleInfo);

			for (String pdbid : experimentInfo.getPdbids())
			{
				IdentifierType identifier = new IdentifierType();

				identifier.setTypeAttr("pdb");
				identifier.setValue(pdbid);

				mods.getModsGroup().add(identifier);				
			}

			GenreType genre = new GenreType();

			genre.setValue("experiment");

			mods.getModsGroup().add(genre);

			try
			{
				for(String relation : experimentInfo.getRelations())
				{
					RelatedItemType relatedItem = objFactory.createRelatedItemType();
					relatedItem.setTypeAttr("otherVersion");

					OriginInfoType originInfoType = objFactory.createOriginInfoType();
					originInfoType.getPlaceOrPublisherOrDateIssued().add(
							objFactory.createOriginInfoTypePublisher("Citation"));

					relatedItem.getModsGroup().add(originInfoType);

					LocationType location = objFactory.createLocationType();
					UrlType url = objFactory.createUrlType();

					url.setValue(relation);
					location.getUrl().add(url);

					relatedItem.getModsGroup().add(location);

					mods.getModsGroup().add(relatedItem);
				}
			} catch (UnsupportedEncodingException e)
			{
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			AbstractType abstractElement = objFactory.createAbstractType();
			abstractElement.setValue(experimentInfo.getabstractTxt());

			mods.getModsGroup().add(abstractElement);

			// authors

			for (String author : experimentInfo.getAuthors())
			{
				NameType name = objFactory.createNameType();

				name.setTypeAttr(NameTypeAttribute.PERSONAL);

				NamePartType namePart = objFactory.createNamePartType();
				namePart.setValue(author);

				name.getNamePartOrDisplayFormOrAffiliation().add(objFactory.createNameTypeNamePart(namePart));

				RoleType.RoleTerm role = objFactory.createRoleTypeRoleTerm();
				role.setTypeAttr(CodeOrText.TEXT);
				role.setValue("author");

				RoleType roleType = objFactory.createRoleType();
				roleType.getRoleTerm().add(role);

				name.getNamePartOrDisplayFormOrAffiliation().add(objFactory.createNameTypeRole(roleType));

				mods.getModsGroup().add(name);
			}

			Marshaller marshaller = jaxbContext.createMarshaller();

			marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", this);
			marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, new Boolean(true));
			marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);

			marshaller.marshal(mods, out);

		} catch (JAXBException j)
		{
			j.printStackTrace();
		}

		return out.toString();
	}

	private String extractTARDISdatafile(File dataFilePath)
	{
		DiffdumpXML ddXML = new DiffdumpXML(); // steve fix this
		return ddXML.extractMetadata(dataFilePath);

	}

	private String extractTARDISdataset(DatasetInfo datasetInfo)
	{
		ByteArrayOutputStream out = new ByteArrayOutputStream();

		try
		{
			JAXBContext jaxbContext = JAXBContext.newInstance("trdDataset2.jaxb");

			trdDataset2.jaxb.ObjectFactory objFactory = new trdDataset2.jaxb.ObjectFactory();

			Dataset dataset = objFactory.createDataset();

			dataset.setCrystalName(datasetInfo.getCrystalName());
			dataset.setResolutionLimit(datasetInfo.getResolutionLimit());
			dataset.setDiffractometerType(datasetInfo.getDiffractometerType());
			dataset.setXraySource((String) datasetInfo.getXraySource());

			if (datasetInfo.getChiAngle() != null)
			{
                try
                {
                    dataset.setChiAngle(Float.parseFloat(datasetInfo.getChiAngle()));
                }
                catch(NumberFormatException e)
                {

                }
			}

			if (datasetInfo.getMosaicSpread() != null)
			{
                try
                {
                    dataset.setMosaicSpread(Float.parseFloat(datasetInfo.getMosaicSpread()));
                }
                catch(NumberFormatException e)
                {

                }
			}

			Marshaller marshaller = jaxbContext.createMarshaller();

			marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", this);
			marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, new Boolean(true));
			marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);

			marshaller.marshal(dataset, out);

			return out.toString();

		} catch (JAXBException j)
		{
			j.printStackTrace();
			return "error";
		}
         catch (Exception e)
        {
            e.printStackTrace();
            return "error";
        }
	}

	@SuppressWarnings("unchecked")
	public Mets writeMETS(String objid, String label, String type, String profile)
	{
        System.out.println("Writing experiment information...\n");

		mets = new Mets();
		mets.setOBJID(objid);
		mets.setLABEL(label);
		mets.setTYPE(type);
		mets.setPROFILE(profile);

		// Header
		MetsHdr metsHdr = new MetsHdr();
		metsHdr.setCREATEDATE(new Date());
		metsHdr.setLASTMODDATE(new Date());

		writeAgent(metsHdr, Role.DISSEMINATOR, Type.ORGANIZATION, experimentInfo.getInstitutionName());

		writeAgent(metsHdr, Role.CREATOR, Type.OTHER, "TARDIS DatasetPackager v1.0");

		mets.getContent().add(metsHdr);

		// Experiment

		writeMODS("J-1", getMODSExperiment(experimentInfo));

		// Premis

		AmdSec amdSec = new AmdSec();
		String techMDid = "A-1";

		writePREMIS(amdSec, techMDid);

		// Filesec

		FileSec fileSec = new FileSec();

		FileGrp fileGrp = new FileGrp();
		fileGrp.setUSE("original");

		// Structmap

		StructMap structMap = new StructMap();
		structMap.setTYPE("logical");

		// A-1 is always premis in this setup
		Div e_Div = writeExperiment("J-1", "A-1");

		int k = 1;
		int i = 2;
		int j = 2;


		for (DatasetInfo di : datasetInfo)
		{

			Div d_Div;
			String mimeType;

			writeMODS("J-" + j, getMODSDataset(di));

			if (di.isRawImages())
			{
				d_Div = writeDataset(e_Div, "J-" + j, "A-" + i);
				mimeType = "application/octet-stream";
				String trdDatasetXML = extractTARDISdataset(di);

				if (!trdDatasetXML.equals("Error"))
				{

					writeTARDISdataset(amdSec, "A-" + i, trdDatasetXML);

				}

			} else
			{
				d_Div = writeDataset(e_Div, "J-" + j);
				mimeType = "application/octet-stream";
			}
			j++;
			i++;

			// copy files here first
			File destDatasetDir = new File(experimentInfo.getDestDir() + File.separator + new File(di.getDir()).getName());
			
			for (File file : new File(di.getDir()).listFiles())
			{
				if (!file.isDirectory())
				{
					try
					{
						copy(file, destDatasetDir);
					} catch (IOException e)
					{
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
			
			di.setDir(destDatasetDir.getAbsolutePath());

            System.out.println("Writing file information...\n");
			for (File file : new File(di.getDir()).listFiles())
			{
				if (!file.isDirectory())
				{

					// if its a legit diffraction image

					if (file.getAbsolutePath().endsWith("osc") || file.getAbsolutePath().endsWith("img")
							|| file.getAbsolutePath().endsWith("adsc") || file.getAbsolutePath().endsWith("mccd")
							|| file.getAbsolutePath().endsWith("mar345") || file.getAbsolutePath().endsWith("mar3450"))
					{ // cause if diffdump crashes, it's all over..
						String trdDatafileXML = extractTARDISdatafile(file);

						if (!trdDatafileXML.equals("Error"))
						{
							writeTARDISdatafile(amdSec, "A-" + i, trdDatafileXML);

							d_Div.getContent().add(writeFilePointer("F-" + k));
							fileGrp.getContent().add(
									writeFileInformation("F-" + k, file.length(), mimeType, file.getName(),
											"TODO:checksumming", Checksumtype.MD5, "file://"
													+ new File(file.getParent()).getName() + "/"
													+ file.getName(), "A-" + i));
							i++;
						} else
						{
							d_Div.getContent().add(writeFilePointer("F-" + k));
							fileGrp.getContent().add(
									writeFileInformation("F-" + k, file.length(), mimeType, file.getName(),
											"TODO:checksumming", Checksumtype.MD5, "file://"
													+ new File(file.getParent()).getName() + "/"
													+ file.getName()));
						}
					}
					else
					{
						d_Div.getContent().add(writeFilePointer("F-" + k));
						fileGrp.getContent().add(
								writeFileInformation("F-" + k, file.length(), mimeType, file.getName(),
										"TODO:checksumming", Checksumtype.MD5, "file://"
													+ new File(file.getParent()).getName() + "/"
												+ file.getName()));
					}

				}

				k++;
			}

			e_Div.getContent().add(d_Div);

		}

		mets.getContent().add(amdSec);

		fileSec.getContent().add(fileGrp);

		mets.getContent().add(fileSec);

		structMap.getContent().add(e_Div);

		mets.getContent().add(structMap);

		try
		{
			// mets.validate(new MetsValidator());

			File METSfile = new File(experimentInfo.getDestDir() + File.separator + "METS.xml");

			FileOutputStream out = new FileOutputStream(METSfile);
			mets.write(new MetsWriter(out));
			out.close();

			System.out.println("Success! File written to " + METSfile.getAbsolutePath() + " \nCopy this file and its data to a web accessible location and register on tardis.edu.au");

		} catch (MetsException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (FileNotFoundException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return mets;

	}

	public boolean validatePackage()
	{
		boolean test = true;

		for (DatasetInfo di : datasetInfo)
		{
            if(di.getDescription().equals(""))
            {
				System.out.println("Missing dataset title");
				test = false;
            }
			if (!new File(di.getDir()).isDirectory())
			{
				System.out.println("Location " + di.getDir() + " is not a directory");
				test = false;
			} else
			{
				if (di.isRawImages())
				{
					if (new File(di.getDir()).listFiles().length == 0)
					{
						System.out.println("No files in Dataset directory: " + di.getDir());
						test = false;
					}
				} else
				{
					di.getDir();
				}
			}
		}

		return test;
	}

	public static void main(String[] args)
	{
		// -Djava.library.path=/Users/steve/Downloads/DiffractionImage/.libs

		ArrayList<Packager> swordPacklist = new ArrayList<Packager>();

		String institutionName = "Monash University";
		
		// 3H7T

		ArrayList<String> authors3H7T = new ArrayList<String>();

		authors3H7T.add("Buckle A.M.");
		
		ArrayList<String> pdbs3H7T = new ArrayList<String>();

		pdbs3H7T.add("3H7T");
		
		ArrayList<String> citations3H7T = new ArrayList<String>();

		citations3H7T.add("http://www.ncbi.nlm.nih.gov/pubmed/19427318?ordinalpos=1&itool=EntrezSystem2.PEntrez.Pubmed.Pubmed_ResultsPanel.Pubmed_DefaultReportPanel.Pubmed_RVDocSum");

		ExperimentInfo experimentInfo3H7T = new ExperimentInfo(pdbs3H7T,
				"Crystal structure of scabies mite inactivated protease paralogue S-D1 (SMIPP-S-D1)", authors3H7T, "Abstract Text",
						citations3H7T, new File(""), "Monash University");

		String destDir3H7T = "/Users/steve/Desktop/Datasets/3H7T";

		ArrayList<DatasetInfo> datasetInfo3H7T = new ArrayList<DatasetInfo>();

		datasetInfo3H7T.add(new DatasetInfo("/Users/steve/Desktop/Datasets/3H7T_SANDBOX/images",
				"Native 2.0 Angstroms", "SMIPP-S-D1", "CCD", 2.0f,
				"APS 17-D", null, null));		

		datasetInfo3H7T.add(new DatasetInfo("Ancillary Files", "/Users/steve/Desktop/Datasets/3H7T_SANDBOX/ancilliary"));

		swordPacklist.add(new Packager(datasetInfo3H7T, experimentInfo3H7T));

		// now validate and write them all

		boolean totalValidation = true;

		for (Packager swordPackage : swordPacklist)
		{
			if (!swordPackage.validatePackage())
			{
				totalValidation = false;
				System.out.println("VALIDATION FAILED on " + swordPackage.getExperimentInfo().getPdbids() + "\n");
			}
		}

		if (totalValidation)
		{
			System.out.println("Validation passed on experiments, packaging...");
			// loop through and write
		} else
		{
			System.out.println("\nValidation failed on 1 or more experiments, packaging not run");
		}

		for (Packager swordPackage : swordPacklist)
		{
			swordPackage.writeMETS("J-1", swordPackage.getExperimentInfo().getTitle(), "study",
					"Scientific Dataset Profile 1.0");
		}

	}

	// Copies src file to dst dir.
	private static void copy(File src, File dst) throws IOException
	{
        System.out.println("Copying " + src.getName() + " to " + dst.getAbsolutePath());
        
		InputStream in = new FileInputStream(src);
		if(!dst.exists())
		{
			dst.mkdirs();
		}
		
		OutputStream out = new FileOutputStream(dst + File.separator + src.getName());

		// Transfer bytes from in to out
		byte[] buf = new byte[1024];
		int len;
		while ((len = in.read(buf)) > 0)
		{
			out.write(buf, 0, len);
		}
		in.close();
		out.close();
	}

	@Override
	public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix)
	{
		if (namespaceUri.equals("http://www.loc.gov/mods/v3"))
		{
			return "mods";
		} else if (namespaceUri.equals("http://www.w3.org/1999/xlink"))
		{
			return "xlink";
		} else if (namespaceUri.startsWith("http://www.tardis.edu.au/schemas"))
		{
			return "trd";
		} else
		{
			return "md";
		}
	}

	private static class ReadWriteTextFile
	{

		/**
		 * Fetch the entire contents of a text file, and return it in a String.
		 * This style of implementation does not throw Exceptions to the caller.
		 * 
		 * @param aFile
		 *            is a file which already exists and can be read.
		 */
		public static String getContents(File aFile)
		{
			// ...checks on aFile are elided
			StringBuilder contents = new StringBuilder();

			try
			{
				// use buffering, reading one line at a time
				// FileReader always assumes default encoding is OK!
				BufferedReader input = new BufferedReader(new FileReader(aFile));
				try
				{
					String line = null; // not declared within while loop
					/*
					 * readLine is a bit quirky : it returns the content of a
					 * line MINUS the newline. it returns null only for the END
					 * of the stream. it returns an empty String if two newlines
					 * appear in a row.
					 */
					while ((line = input.readLine()) != null)
					{
						contents.append(line);
						contents.append(System.getProperty("line.separator"));
					}
				} finally
				{
					input.close();
				}
			} catch (IOException ex)
			{
				ex.printStackTrace();
			}

			return contents.toString();
		}

	}
}